package org.acme.controller;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.lowagie.text.pdf.BaseFont;
import com.opencsv.CSVReader;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import org.acme.bean.dto.BaseResponse;
import org.apache.commons.text.StringSubstitutor;
import org.xhtmlrenderer.pdf.ITextRenderer;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


@Path("/pdf")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class PdfController {

    static final String CSV_ROOT = "csv/";
    static final String CSV_TYPE = ".csv";
    static final String QRCODE_BASE = "qrcode_";
    static final String TEMPLATE_ROOT = "template/";
    static final String TEMPLATE_TYPE = ".html";
    static final String FONT_ROOT = "font/";
    static final String FONT_DEFAULT = "meiryo.ttf";
    static final String OUTPUT_ROOT = "output/";
    static final String OUTPUT_TYPE = ".pdf";

    @GET
    @Path("/format")
    public BaseResponse<String> format(
            @QueryParam("csv") String csv,
            @QueryParam("template") String template,
            @QueryParam("font") String font,
            @QueryParam("output") String output
    ) {
        String csvPath = CSV_ROOT + csv + CSV_TYPE;
        String inputHtmlPath = TEMPLATE_ROOT + template + TEMPLATE_TYPE;
        if (Objects.isNull(font) || font.isEmpty()) {
            font = FONT_DEFAULT;
        }
        String fontPath = FONT_ROOT + font;
        String outputPdfPath = OUTPUT_ROOT + output + OUTPUT_TYPE;

        // value
        Map<String, String> valuesMap = new HashMap<>();
        try {
            try (CSVReader reader = new CSVReader(new FileReader(csvPath))) {
                String[] nextLine;
                while ((nextLine = reader.readNext()) != null) {
                    if (nextLine.length >= 2) {
                        if(nextLine[0].startsWith(QRCODE_BASE)){
                            valuesMap.put(nextLine[0], "data:image/png;base64,"+createQrcode(nextLine[1]));
                        }else {
                            valuesMap.put(nextLine[0], nextLine[1]);
                        }
                    }
                }
            }

            try (OutputStream os = new FileOutputStream(outputPdfPath)) {
                ClassLoader classLoader = PdfController.class.getClassLoader();
                File baseFile = new File(classLoader.getResource(inputHtmlPath).getFile()).getParentFile();
                URL resourceUrl = classLoader.getResource(inputHtmlPath);
                URI resourceUri = resourceUrl.toURI();
                java.nio.file.Path path = Paths.get(resourceUri);
                String htmlContent = Files.readString(path);

                // format
                StringSubstitutor sub = new StringSubstitutor(valuesMap);
                String result = sub.replace(htmlContent);

                // ITextRenderer のインスタンスを作成する
                ITextRenderer renderer = new ITextRenderer();
                // font
                renderer.getFontResolver().addFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
                // base url (img)
                renderer.setDocumentFromString(htmlContent, baseFile.toURI().toString());
                renderer.setDocumentFromString(result);
                renderer.layout();
                renderer.createPDF(os);

                System.out.println("PDF ビルドが成功しました: " + outputPdfPath);
            } catch (Exception e) {
                e.printStackTrace();
            }

            return BaseResponse.success(outputPdfPath);
        } catch (Exception e) {
            e.printStackTrace();
            return BaseResponse.failed();
        }
    }

    private static String createQrcode(String data) {
        int width = 250;
        int height = 250;

        try {
            // 设置编码提示
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

            // 生成二维码位矩阵
            BitMatrix matrix = new MultiFormatWriter().encode(data, BarcodeFormat.QR_CODE, width, height, hints);

            // 将BitMatrix转换为BufferedImage
            BufferedImage image = new BufferedImage(matrix.getWidth(), matrix.getHeight(), BufferedImage.TYPE_INT_RGB);
            for (int x = 0; x < matrix.getWidth(); x++) {
                for (int y = 0; y < matrix.getHeight(); y++) {
                    image.setRGB(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
                }
            }

            // 将BufferedImage写入ByteArrayOutputStream
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(image, "png", baos);
            baos.flush();

            // 转换为Base64字符串
            String base64Image = Base64.getEncoder().encodeToString(baos.toByteArray());

            // 输出Base64字符串
            System.out.println("data:image/png;base64," + base64Image);

            baos.close();

            return base64Image;
        } catch (Exception e) {
            e.printStackTrace();
        }
		return null;
	}

}
